package com.fenda.reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理模式：
 *      我们说我们的业务处理类（例如useroperator类，）希望代码是纯粹的业务代码，不参杂一些系统日志层面的业务，那么我们希望有一个
 *      代理类能够帮我们统一处理系统日志业务，而不会侵入我们的业务代码
 *
 *  具体的业务场景：
 *      我们说要记录用户的每一次操作日志：调用的哪个方法，方法的参数是什么，方法执行了多长时间
 *
 *  动态代理：
 *      在代理的需求上，通吃所有的被代理方法
 *      JDK的动态代理：两个关键核心类：Proxy\InvocationHandler
 *
 * Created by huanggc on 2019/11/8.
 */

interface UserInterface{
    public void addUser(String username);
    public void deleteUser(String username);
    public void updateUser(String username,String username1);
}


class UserOperator implements UserInterface{
    public void addUser(String username){
        System.out.println("添加用户代码");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void deleteUser(String username){
        System.out.println("删除用户代码");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateUser(String username, String username1) {
        System.out.println("修改用户代码");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class UserProxyStatic implements UserInterface{
    UserOperator uo;//代理模式
    public UserProxyStatic(UserOperator uo) {
        this.uo = uo;
    }

    public void addUser(String username){
        System.out.println("添加用户日志===================");
        System.out.println("方法参数username:" + username);
        long start = System.currentTimeMillis();//开始时间
        uo.addUser(username);
        long end = System.currentTimeMillis();//结束时间
        System.out.println("添加用户用了：" + (end -start) + "ms");
    }

    public void deleteUser(String username){
        System.out.println("删除用户日志===================");
        System.out.println("方法参数username:" + username);
        long start = System.currentTimeMillis();//开始时间
        uo.deleteUser(username);
        long end = System.currentTimeMillis();//结束时间
        System.out.println("删除用户用了：" + (end -start) + "ms");
    }

    @Override
    public void updateUser(String username, String username1) {
        System.out.println("修改用户日志===================");
        System.out.println("方法参数username:" + username);
        System.out.println("方法参数username1:" + username1);
        long start = System.currentTimeMillis();//开始时间
        uo.updateUser(username,username1);
        long end = System.currentTimeMillis();//结束时间
        System.out.println("修改用户用了：" + (end -start) + "ms");
    }
}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;

    public MyInvocationHandler(Object obj) {
        this.obj = obj;
    }

    /**
     *
     * @param proxy 此参数很复杂，忽略
     * @param method 被代理的方法
     * @param args  被代理的方法的传入的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("被代理的方法名：" + method.getName());
        System.out.println("被代理的方法参数个数：" + method.getParameterCount());
        Class<?>[] parameterTypes = method.getParameterTypes();
        int index = 0;
        for(Class paramType : parameterTypes){
            System.out.println("被代理的方法参数类型：" + paramType.getName());
            System.out.println("被代理的方法参数值：" + args[index]);
            index++;
        }
        long start = System.currentTimeMillis();//开始时间
        Object ret = method.invoke(obj, args);//反射调用被代理对象的方法并获取返回值
        long end = System.currentTimeMillis();//结束时间
        System.out.println(method.getName() +  "用了：" + (end -start) + "ms");
        return ret;
    }
}


public class JingtaiDaili {
    public static void main(String[] args) {
       /* UserOperator uo = new UserOperator();
        UserProxyStatic ups = new UserProxyStatic(uo);
        ups.addUser("秦弘");
        ups.deleteUser("翁国坛");*/
        UserOperator ui = new UserOperator();//被代理对象

        Object o = Proxy.newProxyInstance(ReflectDemo.class.getClassLoader(), UserOperator.class.getInterfaces() , new MyInvocationHandler(ui));
        System.out.println(o.getClass().getName());
        UserInterface proxy = (UserInterface)o;
        proxy.addUser("秦弘");
        proxy.deleteUser("翁国坛");
        proxy.updateUser("秦弘","翁国坛");

    }
}
